#define		_Exception_Vector	0xD0037400
#define		 pExceptionRESET	( *((volatile unsigned long *)(_Exception_Vector + 0x0)) )
#define		 pExceptionUNDEF	( *((volatile unsigned long *)(_Exception_Vector + 0x4)) )
#define		 pExceptionSWI		( *((volatile unsigned long *)(_Exception_Vector + 0x8)) )
#define 	pExceptionPABORT	( *((volatile unsigned long *)(_Exception_Vector + 0xc)) )
#define 	pExceptionDABORT	( *((volatile unsigned long *)(_Exception_Vector + 0x10)) )
#define	        pExceptionRESERVED	( *((volatile unsigned long *)(_Exception_Vector + 0x14)) )
#define		pExceptionIRQ		( *((volatile unsigned long *)(_Exception_Vector + 0x18)) )
#define		pExceptionFIQ		( *((volatile unsigned long *)(_Exception_Vector + 0x1c)) )


#define    VIC0INTENCLEAR         ( *((volatile unsigned long *)(0xF2000014)))
#define    VIC1INTENCLEAR         ( *((volatile unsigned long *)(0xF2100014)))
#define    VIC2INTENCLEAR         ( *((volatile unsigned long *)(0xF2200014)))
#define    VIC3INTENCLEAR         ( *((volatile unsigned long *)(0xF2300014)))

#define    VIC0INTSELECT         ( *((volatile unsigned long *)(0xF200000C)))
#define    VIC1INTSELECT         ( *((volatile unsigned long *)(0xF210000C)))
#define    VIC2INTSELECT         ( *((volatile unsigned long *)(0xF220000C)))
#define    VIC3INTSELECT         ( *((volatile unsigned long *)(0xF230000C)))

#define    VIC0ADDR         ( *((volatile unsigned long *)(0xF2000F00)))
#define    VIC1ADDR         ( *((volatile unsigned long *)(0xF2100F00)))
#define    VIC2ADDR         ( *((volatile unsigned long *)(0xF2200F00)))
#define    VIC3ADDR         ( *((volatile unsigned long *)(0xF2300F00)))

#define    VIC0IRQSTATUS         ( *((volatile unsigned long *)(0xF2000000)))
#define    VIC1IRQSTATUS         ( *((volatile unsigned long *)(0xF2100000)))
#define    VIC2IRQSTATUS         ( *((volatile unsigned long *)(0xF2200000)))
#define    VIC3IRQSTATUS         ( *((volatile unsigned long *)(0xF2300000)))


//#define    VIC0VECTADDR         ( *((volatile unsigned long *)(0xF2000100)))
//#define    VIC1VECTADDR         ( *((volatile unsigned long *)(0xF2100100)))
//#define    VIC2VECTADDR         ( *((volatile unsigned long *)(0xF2200100)))
//#define    VIC3VECTADDR         ( *((volatile unsigned long *)(0xF2300100)))

#define    VIC0VECTADDR         0xF2000100
#define    VIC1VECTADDR         0xF2100100
#define    VIC2VECTADDR         0xF2200100
#define    VIC3VECTADDR         0xF2300100

#define    VIC0INTENABLE         ( *((volatile unsigned long *)(0xF2000010)))
#define    VIC1INTENABLE         ( *((volatile unsigned long *)(0xF2100010)))
#define    VIC2INTENABLE         ( *((volatile unsigned long *)(0xF2200010)))
#define    VIC3INTENABLE         ( *((volatile unsigned long *)(0xF2300010)))

#define    VIC0INTCLEAR         ( *((volatile unsigned long *)(0xF2000014)))
#define    VIC1INTCLEAR         ( *((volatile unsigned long *)(0xF2100014)))
#define    VIC2INTCLEAR         ( *((volatile unsigned long *)(0xF2200014)))
#define    VIC3INTCLEAR         ( *((volatile unsigned long *)(0xF2300014)))
extern void IRQ_handler();
void system_initexception( void)
{
    // 设置中断向量表
//    pExceptionUNDEF   = (unsigned long)exceptionundef;
//    pExceptionSWI     = (unsigned long)exceptionswi;
//    pExceptionPABORT  = (unsigned long)exceptionpabort;
//    pExceptionDABORT  = (unsigned long)exceptiondabort;
    pExceptionIRQ     = (unsigned long)IRQ_handler;
    pExceptionFIQ     = (unsigned long)IRQ_handler;
    // 初始化中断控制器
    intc_init();
}
void intc_init(void)
{
    // 禁止所有中断
    VIC0INTENCLEAR = 0xffffffff;
    VIC1INTENCLEAR = 0xffffffff;
    VIC2INTENCLEAR = 0xffffffff;
    VIC3INTENCLEAR = 0xffffffff;
    // 选择中断类型为IRQ
    VIC0INTSELECT = 0x0;
    VIC1INTSELECT = 0x0;
    VIC2INTSELECT = 0x0;
    VIC3INTSELECT = 0x0;
    // 清VICxADDR
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;
}


// 读取VICnIRQSTATUS寄存器，判断其中哪个为1，可知哪个VIC发生中断了
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
    if(ucontroller ==0)
	return VIC0IRQSTATUS;
    else if(ucontroller ==1)
	return VIC1IRQSTATUS;
    else if(ucontroller ==2)
	return VIC2IRQSTATUS;
    else if(ucontroller ==3)
	return VIC3IRQSTATUS;
    else
    {}
    return 0;
}

void irq_handler(void)
{

    unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
    int i=0;
    void (*isr)(void)=0;

    for(; i<4; i++)
    {
        if(intc_getvicirqstatus(i) != 0)
        {
            isr = (void (*)(void)) vicaddr[i];
            break;
        }
    }
    (*isr)();
}
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
    if(intnum <32) {
	*((volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)))=(unsigned) handler;
    }
    else if(intnum <64) {
	*((volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)))=(unsigned) handler;
    }
    else if(intnum <96) {
	*((volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)))=(unsigned) handler;
    }
    else {
	*((volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)))=(unsigned) handler;
    }
}
void intc_enable(unsigned long intnum)
{
    unsigned long temp;
    if(intnum<32)
    {
        temp = VIC0INTENABLE;
        temp |= (1<<intnum);
        VIC0INTENABLE = temp;
    }
    else if(intnum<64)
    {
        temp = VIC1INTENABLE;
        temp |= (1<<(intnum-32));
        VIC1INTENABLE = temp;
    }
    else if(intnum<96)
    {
        temp = VIC2INTENABLE;
        temp |= (1<<(intnum-64));
        VIC2INTENABLE = temp;
    }
    else if(intnum<127)
    {
        temp = VIC3INTENABLE;
        temp |= (1<<(intnum-96));
        VIC3INTENABLE = temp;
    }
    else
    {
        VIC0INTENABLE = 0xFFFFFFFF;
        VIC1INTENABLE = 0xFFFFFFFF;
        VIC2INTENABLE = 0xFFFFFFFF;
        VIC3INTENABLE = 0xFFFFFFFF;
    }    
}

void intc_clearvectaddr()
{
    // 清VICxADDR
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;
}
